package middleware

import (
	"context"
	"errors"
	"github.com/golang-jwt/jwt/v4"
	"github.com/zeromicro/go-zero/core/logx"
	"github.com/zeromicro/go-zero/rest/httpx"
	"net/http"
	"net/http/httputil"
	"xialou_platform/app/errorx"
	"xialou_platform/app/jwtx"
)

type AuthMiddleware struct {
	secret       string
	allowOptions map[string]bool
}

func NewAuthMiddleware(secret string) *AuthMiddleware {
	return &AuthMiddleware{
		secret: secret,
		//jwtModel:  jwtModel,
	}
}

func (m *AuthMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {

	return func(w http.ResponseWriter, r *http.Request) {

		authorization := r.Header.Get("Authorization")

		//if m.jwtModel.IsBlack(r.Context(), authorization) {
		//	unauthorized(w, r, errorx.NewErrMsg("Login Expire"))
		//	return
		//}
		ctx := r.Context()
		if len(authorization) > 0 {
			var claim jwtx.MyClaims
			tok, err := jwt.ParseWithClaims(authorization, &claim, func(token *jwt.Token) (interface{}, error) {
				return []byte(m.secret), nil
			})

			//tok, err := parser.ParseToken(r, m.secret, "")
			if err != nil {
				m.unauthorized(w, r, err)
				return
			}

			if !tok.Valid {
				m.unauthorized(w, r, errInvalidToken)
				return
			}
			if claim.Uid != 0 {
				ctx = context.WithValue(ctx, "claim", claim)
			}
		}
		next(w, r.WithContext(ctx))
	}
}

func (m *AuthMiddleware) unauthorized(w http.ResponseWriter, r *http.Request, err error) {

	if err != nil {
		detailAuthLog(r, err.Error())
	} else {
		detailAuthLog(r, noDetailReason)
	}

	// if user not setting HTTP header, we set header with 401
	w.WriteHeader(http.StatusUnauthorized)

	httpx.WriteJson(w, http.StatusBadRequest,
		errorx.NewMsgCodeError(errorx.UnLoginCode, "请登录"))

}

const (
	jwtAudience    = "aud"
	jwtExpire      = "exp"
	jwtId          = "jti"
	jwtIssueAt     = "iat"
	jwtIssuer      = "iss"
	jwtNotBefore   = "nbf"
	jwtSubject     = "sub"
	noDetailReason = "no detail reason"
)

var (
	errInvalidToken = errors.New("invalid auth token")
	errNoClaims     = errors.New("no auth params")
)

func detailAuthLog(r *http.Request, reason string) {
	// discard dump error, only for debug purpose
	details, _ := httputil.DumpRequest(r, true)
	logx.Errorf("authorize failed: %s\n=> %+v", reason, string(details))
}
